package com.bilibili.server.service;

import com.bilibili.autoconfig.template.OssTemplate;
import com.bilibili.commons.Constants;
import com.bilibili.commons.exception.TanHuaException;
import com.bilibili.dubbo.api.db.UserInfoApi;
import com.bilibili.dubbo.api.mongo.CommentApi;
import com.bilibili.dubbo.api.mongo.MovementApi;
import com.bilibili.model.db.UserInfo;
import com.bilibili.model.enums.CommentType;
import com.bilibili.model.mongo.Comment;
import com.bilibili.model.mongo.Movement;
import com.bilibili.model.mongo.Visitors;
import com.bilibili.model.vo.MovementVo;
import com.bilibili.model.vo.MovementsVo;
import com.bilibili.model.vo.PageResult;
import com.bilibili.model.vo.VisitorsVo;
import com.bilibili.server.interceptor.UserHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.bson.types.ObjectId;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author HuangRongFu
 * 2021/11/21 星期日4:51 下午
 */

@Service
@Slf4j
public class MovementService {

    @Autowired
    private OssTemplate ossTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private UserFreezeService userFreezeService;

    @Autowired
    private MqMessageService mqMessageService;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @DubboReference
    private MovementApi movementApi;

    @DubboReference
    private UserInfoApi userInfoApi;

    @DubboReference
    private CommentApi commentApi;

    /**
     * 发布动态
     *
     * @param: vo
     * @param: imageContent[]
     * @Return: null
     */
    public void PostMovement(MovementVo vo, MultipartFile[] imageContent) {

        userFreezeService.checkUserStatus(3, UserHolder.getUser().getMobile());

        //1 判断发布动态内容是否存在
        if (StringUtils.isEmpty(vo.getTextContent())) {

            throw new TanHuaException("动态文本内容不能为空!");
        }

        //2 获取当前登录用户id
        Long userId = UserHolder.getUserId();

        //创建一个集合接收imageUrl
        ArrayList<String> imageUrlList = new ArrayList<>();

        //3 将动态中的图片上传到阿里oss
        if (null != imageContent && imageContent.length > 0)
            try {
                for (MultipartFile image : imageContent) {
                    //4 获取到图片的url 字符串
                    String imageUrl = ossTemplate.upload(image.getOriginalFilename(), image.getInputStream());
                    imageUrlList.add(imageUrl);
                }
            } catch (IOException e) {

                log.error("动态发布失败", e);
                throw new TanHuaException("动态发布失败");
            }

        Movement pojo = new Movement();
        BeanUtils.copyProperties(vo, pojo);

        //5 将数据封装到Movement中
        pojo.setId(new ObjectId());
        pojo.setUserId(userId);//设置发送动态的作者id
        pojo.setMedias(imageUrlList);
        pojo.setLocationName(vo.getLocation());

        //调用api
        movementApi.publish(pojo);

        //操作记录到logbiao
        mqMessageService.sendLogMessage(UserHolder.getUserId(), "0201", "movement", pojo.getId().toHexString());

        //发布动态审核消息
        mqMessageService.sendAudiMessage(pojo.getId().toHexString());
    }

    /**
     * 用户动态  只是查询个人的
     *
     * @param: page
     * @param: pageSize
     * @param: userId
     * @Return: ResponseEntity
     */
    public PageResult<MovementsVo> findByUserId(Long page, Long pageSize, Long userId) {

        //通过用户id去查询时间线表 看记录条数
        PageResult pageResult = movementApi.findByUserId(page, pageSize, userId);

        //获取items对象
        List<Movement> items = pageResult.getItems();

        ArrayList<MovementsVo> voList = new ArrayList<>();

        //如果返回的items不为空 则将 items复制给voList
        if (CollectionUtils.isNotEmpty(items)) {

            //作者信息
            UserInfo userInfo = userInfoApi.findById(userId);

            for (Movement item : items) {

                MovementsVo vo = MovementsVo.init(userInfo, item);

                voList.add(vo);
            }
        }

        pageResult.setItems(voList);

        mqMessageService.sendLogMessage(UserHolder.getUserId(), "0202", "movement", userId.toString());

        return pageResult;
    }

    /**
     * 好友动态
     *
     * @param: page
     * @param: pageSize
     * @Return: ResponseEntity
     */
    public PageResult<MovementsVo> findFriendMovement(Long page, Long pageSize) {

        //1 先通过用户id 去查时间线表 就可以获取好友ids
        PageResult pageResult = movementApi.findFriendMovement(page, pageSize, UserHolder.getUserId());

        List<Movement> movementList = pageResult.getItems();

        //方法抽取成 convert2Vo
        List<MovementsVo> voList = convert2Vo(movementList);

        pageResult.setItems(voList);

        return pageResult;
    }

    /**
     * 推荐动态
     *
     * @param: page
     * @param: pageSize
     * @Return: ResponseEntity
     */
    public PageResult<MovementsVo> findRecommend(Long page, Long pageSize) {

        //1 推荐给登录用户 获取登录用户id
        //2 从Redis中获取当前用户的推荐pid列表
        String key = Constants.MOVEMENTS_RECOMMEND + UserHolder.getUserId();
        String recommendMovementPids = stringRedisTemplate.opsForValue().get(key);

        List<Movement> movementList = new ArrayList<>();
        long total = 0l;
        //2.1 如果没有值 就随机推荐十条动态
        if (StringUtils.isEmpty(recommendMovementPids)) {

            movementList = movementApi.RandomMovement();
            total = 10l;

        } else {
            //2.2 有值就通过pid去查询动态表 回显动态
            // 将pids列表 通过逗号分割
            String[] recommendMovementPidsArr = StringUtils.split(recommendMovementPids, ",");

            //计算是否需要分页
            long start = (page - 1) * pageSize;

            if (recommendMovementPidsArr.length > start) {

                //获取动态的pid
                List<Long> pidList = Arrays.stream(recommendMovementPidsArr).skip(start).limit(pageSize)
                        //.map 是把字符串类型的pid 转化成Long类型
                        .map(idStr -> Long.valueOf(idStr)).collect(Collectors.toList());

                //通过获取的pidList 去批量查数据库
                movementList = movementApi.findByPids(pidList);
            }

            total = recommendMovementPidsArr.length;
        }
        //3 构建Vo对象
        List<MovementsVo> voList = convert2Vo(movementList);

        //4 返回PageReuslt
        return new PageResult(page, pageSize, total, voList);
    }

    /**
     * 提出来的公共方法
     *
     * @param: movementList
     * @Return: List
     */
    private List<MovementsVo> convert2Vo(List<Movement> movementList) {

        List<MovementsVo> voList = new ArrayList<>();

        if (CollectionUtils.isNotEmpty(movementList)) {
            //2 通过好友的id  补上好友的详细信息
            List<Long> userIds = movementList.stream().map(Movement::getUserId).collect(Collectors.toList());

            Map<Long, UserInfo> userInfoMap = userInfoApi.findByIds(userIds, null);

            for (Movement movement : movementList) {

                UserInfo userInfo = userInfoMap.get(movement.getUserId());

                MovementsVo vo = MovementsVo.init(userInfo, movement);

                //判断用户是否点赞过了
                String key = Constants.MOVEMENTS_INTERACT_KEY + movement.getId().toHexString();
                String whoKey = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();

                //添加标记
                if (stringRedisTemplate.opsForHash().hasKey(key, whoKey)) {

                    vo.setHasLiked(1);
                }

                //判断用户是否喜欢过
                String loveKey = Constants.MOVEMENT_LOVE_HASHKEY + UserHolder.getUserId();
                if (stringRedisTemplate.opsForHash().hasKey(key, loveKey)) {

                    vo.setHasLoved(1);
                }

                voList.add(vo);
            }
        }

        return voList;
    }

    /**
     * 查询单条动态
     *
     * @param: userId
     * @Return: MovementsVo
     */
    public MovementsVo findById(String movementId) {

        Movement movement = movementApi.findMovementById(movementId);

        UserInfo userInfo = userInfoApi.findById(movement.getUserId());

        return MovementsVo.init(userInfo, movement);
    }

    /**
     * 动态 点赞
     *
     * @param: movementId
     * @Return: ResponseEntity
     */
    public Integer like(String movementId) {

        userFreezeService.checkUserStatus(2, UserHolder.getUser().getMobile());

        //构建pojo
        Comment comment = new Comment();

        //动态id
        comment.setPublishId(new ObjectId(movementId));

        //点赞的人
        comment.setUserId(UserHolder.getUserId());

        //评论类型
        comment.setCommentType(CommentType.LIKE.getType());

        //添加点赞记录
        Integer count = commentApi.add(comment);

        String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
        String whoKey = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();

        stringRedisTemplate.opsForHash().put(key, whoKey, "1");

        mqMessageService.sendLogMessage(UserHolder.getUserId(), "0203", "movement", movementId);

        return count;
    }

    /**
     * 动态 取消点赞
     *
     * @param: movementId
     * @Return: ResponseEntity
     */
    public Integer dislike(String movementId) {

        userFreezeService.checkUserStatus(2, UserHolder.getUser().getMobile());

        //构建pojo
        Comment comment = new Comment();

        //动态id
        comment.setPublishId(new ObjectId(movementId));

        //点赞的人
        comment.setUserId(UserHolder.getUserId());

        //评论类型
        comment.setCommentType(CommentType.LIKE.getType());

        //删除点赞记录
        Integer count = commentApi.remove(comment);

        String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
        String whoKey = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();

        stringRedisTemplate.opsForHash().delete(key, whoKey);

        mqMessageService.sendLogMessage(UserHolder.getUserId(), "0206", "movement", movementId);

        return count;
    }

    /**
     * 动态 喜欢
     *
     * @param: movementId
     * @Return: ResponseEntity
     */
    public Integer love(String movementId) {

        userFreezeService.checkUserStatus(2, UserHolder.getUser().getMobile());

        //构建pojo
        Comment comment = new Comment();

        //动态id
        comment.setPublishId(new ObjectId(movementId));

        //点赞的人
        comment.setUserId(UserHolder.getUserId());

        //评论类型
        comment.setCommentType(CommentType.LOVE.getType());

        //添加点赞记录
        Integer count = commentApi.add(comment);

        String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
        String whoKey = Constants.MOVEMENT_LOVE_HASHKEY + UserHolder.getUserId();

        stringRedisTemplate.opsForHash().put(key, whoKey, "1");

        mqMessageService.sendLogMessage(UserHolder.getUserId(), "0204", "movement", movementId);

        return count;
    }

    /**
     * 动态 取消喜欢
     *
     * @param: movementId
     * @Return: ResponseEntity
     */
    public Integer unlove(String movementId) {

        userFreezeService.checkUserStatus(2, UserHolder.getUser().getMobile());

        //构建pojo
        Comment comment = new Comment();

        //动态id
        comment.setPublishId(new ObjectId(movementId));

        //点赞的人
        comment.setUserId(UserHolder.getUserId());

        //评论类型
        comment.setCommentType(CommentType.LOVE.getType());

        //删除点赞记录
        Integer count = commentApi.remove(comment);

        String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
        String whoKey = Constants.MOVEMENT_LOVE_HASHKEY + UserHolder.getUserId();

        stringRedisTemplate.opsForHash().delete(key, whoKey);

        mqMessageService.sendLogMessage(UserHolder.getUserId(), "0207", "movement", movementId);

        return count;
    }

    /**
     * 谁看过我
     *
     * @Return: List<VisitorsVo>
     */
    public List<VisitorsVo> queryVisitorsList() {
        //查询访问时间
        String key = Constants.VISITORS_USER;

        String hashKey = String.valueOf(UserHolder.getUserId());

        String value = (String) stringRedisTemplate.opsForHash().get(key, hashKey);

        Long date = StringUtils.isEmpty(value) ? null : Long.valueOf(value);

        //查询看过我的id集合
        List<Visitors> visitorsList = movementApi.queryVisitorsList(UserHolder.getUserId(), date);

        List<VisitorsVo> voList = new ArrayList<>();

        if (CollectionUtils.isNotEmpty(visitorsList)) {

            List<Long> ids = visitorsList.stream().map(Visitors::getVisitorUserId).collect(Collectors.toList());

            Map<Long, UserInfo> userInfoMap = userInfoApi.findByIds(ids, null);

            for (Visitors visitors : visitorsList) {

                UserInfo userInfo = userInfoMap.get(visitors.getVisitorUserId());

                voList.add(VisitorsVo.init(userInfo, visitors));
            }
        }

        return voList;
    }
}
